package main.java.exercise;

import main.java.framework.StudentInformation;
import main.java.framework.StudentSolution;

public class StudentSolutionImplementation implements StudentSolution {

    @Override
    public StudentInformation provideStudentInformation() {
        return new StudentInformation(
                "", // Vorname
                "", // Nachname
                "" // Matrikelnummer
        );
    }

    public char getCharAt(String s, int i) {
        if (i >= s.length() || i < 0)
            return '{';
        return s.charAt(i);
    }

    private boolean lookupKey(InnerNode root, Key key, int i) {
        Node node = root.getChild(key.charAt(i));
        if (node == null)
            return false;
        if (node.isLeaf())
            return ((LeafNode) node).containsKey(key);
        return lookupKey(((InnerNode) node), key, i + 1);
    }

    public boolean lookupKey(InnerNode root, Key key) {
        return lookupKey(root, key, 0);
    }

    private void insertKey(InnerNode root, LeafNode leafNode, int i) {
        // prevent repeated keyCharAt calls
        char c = leafNode.keyCharAt(i);
        Node node = root.getChild(c);

        // in case there is already a preexisting path
        if (node != null) {
            // no reinserting the same elements
            if (node.isLeaf() && leafNode.hasSameKey((LeafNode) node))
                return;
            // not the same key, but still a leaf
            if (node.isLeaf()) {
                // insert node in place of the leaf, handle input and leaf
                // accordingly
                root.attachInnerNode(c);
                insertKey(root, (LeafNode) node, i);
                insertKey(root, leafNode, i);
                return;
            }
            // is a node,
            insertKey((InnerNode) node, leafNode, i + 1);
        } else {
            // no luck, try entire search space
            for (int j = 'a'; j <= '{'; j++) {
                node = root.getChild(c);
                // there already exists a node, switch to inserting a node
                // instead of further attempting to insert a leaf
                if (node != null) {
                    root.attachInnerNode(c);
                    insertKey(root, leafNode, i);
                    return;
                }
            }
            // root is actually node-less and leaf-less, insert leaf
            root.attachLeafNode(c, leafNode);
        }
    }

    public void insertKey(InnerNode root, LeafNode leafNode) {
        insertKey(root, leafNode, 0);
    }
}
